﻿namespace Aldart.WebSockets.Server
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using log4net;

    /// <summary>
    /// Class used for reading and writing WebSockets headers.
    /// </summary>
    public class Request
    {
        /// <summary>
        /// Logging object.
        /// </summary>
        private static ILog log = LogManager.GetLogger(typeof(Request));

        /// <summary>
        /// String containing the first line of the request.
        /// </summary>
        private string requestLine;

        /// <summary>
        /// List containg all arguments of the request.
        /// </summary>
        private List<Tuple<string, string>> arguments = new List<Tuple<string, string>>();

        /// <summary>
        /// Array containing the data that is sent or received at the end of the request.
        /// </summary>
        private byte[] data;

        /// <summary>
        /// Initializes a new instance of the Request class.
        /// </summary>
        public Request() {
        }

        /// <summary>
        /// Initializes a new instance of the Request class.
        /// </summary>
        /// <param name="buffer">The buffer from which to read the data.</param>
        /// <param name="offset">Offset where the data begins in the buffer.</param>
        /// <param name="length">Number of bytes to read.</param>
        /// <param name="dataLength">Number of bytes at the end of the request that contain the additional data.</param>
        public Request(byte[] buffer, int offset, int length, int dataLength) {
            // Check parameters for correctness
            if (offset + length > buffer.Length) {
                throw new InvalidRequestException("Given length and offset is at least partially outside of the buffer.");
            }

            if (dataLength > length) {
                throw new InvalidRequestException("Length of additional data may not be longer than the total length.");
            }

            // Parse text part of the request
            UTF8Encoding encoder = new UTF8Encoding();
            string requestText = encoder.GetString(buffer, offset, length - dataLength);
            string[] lines = requestText.Split(new string[] { "\r\n" }, StringSplitOptions.None);

            // First line is the request line, the rest are arguments
            this.requestLine = lines[0];
            for (int i = 1; i < lines.Length; i++) {
                string line = lines[i];
                if (!String.IsNullOrEmpty(line)) {
                    if (line.Contains(":")) {
                        int colonIndex = line.IndexOf(":");
                        this.arguments.Add(new Tuple<string, string>(line.Substring(0, colonIndex), line.Substring(colonIndex + 1)));
                    }
                    else {
                        log.Warn("Header line without a colon found.");
                    }
                }
            }

            // Copy data part of the request
            this.data = new byte[dataLength];
            Array.Copy(buffer, length - dataLength, this.data, 0, dataLength);
        }
    }
}
